import {getCurrentInstance} from 'vue'
import {kebabCase} from "../utils/kebabCase";
import {createPlainEvent} from "../plugins/Event";
import {SimpleFunction} from "../shims";

// focus                -> focus
// itemClick            -> item-click
// updateModelValue     -> update:modelValue
// updateStart          -> update:start
function emitName2ListenName(emitName: string): string {
  const match = emitName.match(/update([A-Z])(.*)/)
  if (match) {
      return `update:${match[1].toLowerCase()}${match[2]}`
  }
  return kebabCase(emitName)!
}
// TODO Parameters<EmitsValue> 是什么
type EventListener<EmitsValue> = EmitsValue extends (...args: any[]) => any ? Parameters<EmitsValue> : never

export type ComponentEvent<Emit> = {
  emit: { [key in keyof Emit]: (...args: EventListener<Emit[key]>) => void },
  on: { [key in keyof Emit]: (cb: (...args: EventListener<Emit[key]>) => void) => void },
  once: { [key in keyof Emit]: (cb: (...args: EventListener<Emit[key]>) => void) => void },
  off: { [key in keyof Emit]: (cb: (...args: EventListener<Emit[key]>) => void) => void },
}

export function getComponentEmit<T>(emitObject: T): T {
  return {
    change: null,
    ...Object.keys(emitObject || {}).reduce((ret: any, key: string) => {
      ret[emitName2ListenName(key)] = (emitObject as any)[key]
      return ret
    }, {} as any)
  }
}

export function useEvent<T>(emitObject: T): ComponentEvent<T> {
  const ctx = getCurrentInstance()!
  const event = createPlainEvent()

  const emit = {} as any;
  const on = {} as any;
  const once = {} as any;
  const off = {} as any;

  Object.keys(emitObject || {}).forEach(key => {
    const kebabCaseName = emitName2ListenName(key)

    emit[key] = (...args: any[]) => {
      //TODO 为啥发两个事件
      ctx.emit(kebabCaseName, ...args)
      event.emit(kebabCaseName, ...args)
      if (key === 'updateModelValue') {
        ctx.emit('change', ...args)
        event.emit('change', ...args)
      }
    }

    on[key] = (fn: SimpleFunction) => event.on(kebabCaseName, fn)
    once[key] = (fn: SimpleFunction) => event.once(kebabCaseName, fn)
    off[key] = (fn: SimpleFunction) => event.once(kebabCaseName, fn)
  })

  return {
    emit, on, once, off
  } as any
}